package com.pinoc.demo.randomlottery;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * @author pinoc
 * @date 2023/11/13
 */
public class Lottery {
	public static void main(String[] args) {
		// 奖品 <--> 奖品库存
		final Map<String, Integer> awardStockMap = new ConcurrentHashMap<>();
		awardStockMap.put("1", 5000);
		awardStockMap.put("2", 1000);
		awardStockMap.put("3", 500);
		awardStockMap.put("5", 100);
		awardStockMap.put("iphone", 1);
		// 6601*10 -6601
		awardStockMap.put("未中奖", 59409);
		// 奖品 <--> 奖品权重 权重默认等于库存
		final Map<String, Integer> awardWeightMap = new ConcurrentHashMap<>(awardStockMap);
		// 日活用户数
		int userNum = 30000;
		// 每天抽奖次数 = 日活数*抽奖次数
		int drawNum = userNum * 3;
		// 每天实际中奖计数
		Map<String, Integer> dailyWinCountMap = new ConcurrentHashMap<>(16);
		// 模拟每次抽奖
		for (int j = 0; j < drawNum; j++) {
			// 排除掉库存为0的奖品
			Map<String, Integer> awardWeightHaveStockMap = awardWeightMap.entrySet().stream().filter(e -> awardStockMap.get(e.getKey()) > 0)
					.collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()));
			int totalWeight = (int) awardWeightHaveStockMap.values().stream().collect(Collectors.summarizingInt(i -> i)).getSum();
			int randNum = new Random().nextInt(totalWeight);
			int prev = 0;
			String choosedAward = null;
			// 按照权重计算中奖区间
			for (Map.Entry<String, Integer> e : awardWeightHaveStockMap.entrySet()) {
				if (randNum >= prev && randNum < prev + e.getValue()) {
					// 落入该奖品区间
					choosedAward = e.getKey();
					break;
				}
				prev = prev + e.getValue();
			}
			// 中奖计数
			dailyWinCountMap.compute(choosedAward, (k, v) -> v == null ? 1 : v + 1);
			// 未中奖不用减库存
			if (!"未中奖".equals(choosedAward)) {
				// 奖品库存一
				awardStockMap.compute(choosedAward, (k, v) -> v - 1);
				if (awardStockMap.get(choosedAward) == 0) {
					// 记录库存为空的顺序
					System.out.printf("奖品：%s 库存为空%n", choosedAward);
				}
			}

		}
		// 每日各奖品中奖计数
		System.out.println("各奖品中奖计数: " + dailyWinCountMap);
	}
}
